/*
 * Copyright (c) 2006-2023, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-06-29     Rbb666       first version
 */

#include <rtthread.h>
#include <rtdevice.h>

#include "drv_gpio.h"
#include "ptc_06.h"
#include "GET_TEST_main.h"

#define LED_PIN     GET_PIN(0, 1)
//#define UART_DEBUG


rt_device_t camera_serial;

struct rt_messagequeue camera_rx_mq;
PTC06 camera;



rt_err_t cb(rt_device_t dev, rt_size_t size)
{
    static uint8_t buf[256];
    if (dev == camera_serial)
    {
        if (rt_mq_send(&camera_rx_mq, &size,
                sizeof(size)) == -RT_EFULL)
        {
            rt_kprintf("camera message queue full!\n");
            return -RT_EFULL;
        }
        return RT_EOK;
    }
    int rl = rt_device_read(dev, 0, &buf,
            size < 256 ? size : 256);
    for (int i = 0; i < rl; i++)
    {
        rt_kprintf("%02x", buf[i]);
    }
    return RT_EOK;
}

int camera_write(uint8_t *buf, uint16_t len)
{
#ifdef UART_DEBUG
    rt_kprintf("write:");
    for (int i = 0; i < len; i++)
    {
        rt_kprintf("%02x ", buf[i]);
    }
    rt_kprintf("\n");
#endif
    return rt_device_write(camera_serial, 0, buf, len);
}

uint32_t camera_read(uint8_t **buf_ptr, int32_t len)
{
    rt_size_t size = 0;
    rt_uint32_t rx_len = 0;
    uint8_t *rx_buf = RT_NULL;
    uint32_t rx_buf_size;
    rt_bool_t buf_size_const = 0;

    rt_ssize_t result = rt_mq_recv(&camera_rx_mq, &size,
            sizeof(rt_size_t), RT_WAITING_FOREVER);
    if (len == READ_ALLOC)
    {
        rx_buf = (uint8_t*) rt_malloc(size);
        *buf_ptr = rx_buf;
        rx_buf_size = size;
    }
    else if (size <= len)
    {
        rx_buf = *buf_ptr;
        rx_buf_size = len;
        buf_size_const = 1;
    }
    else
    {
        // 要清空缓冲区，也只能申请空间了
        rx_buf = (uint8_t*) rt_malloc(size);
        rx_buf_size = size;
        rt_kprintf("预先申请的空间不足或需要抛弃消息体.\n");
    }
    while (result > 0)
    {
        // 调整空间大小
        if (!buf_size_const
                && (rx_buf_size < rx_len + size))
        {
            rx_buf_size = rx_len + size;
            uint8_t *nrx_buf = (uint8_t*) rt_realloc(rx_buf,
                    rx_len + size);
            if (nrx_buf == NULL)
            {
                nrx_buf = (uint8_t*) rt_malloc(
                        rx_len + size);
                if (nrx_buf != NULL)
                {
                    memcpy(nrx_buf, rx_buf, rx_len);
                }
                rt_free(rx_buf);
            }
            rx_buf = nrx_buf;
            *buf_ptr = nrx_buf;
        }
        else if (buf_size_const
                && rx_buf_size < rx_len + size)
        {
            rt_kprintf("预先申请空间不足，导致消息内容被覆盖或内存溢出"); //为了避免消息阻塞在接收缓存区，所以采取覆盖时，先把接收缓冲区内消息读取出来。
        }
        // 判断空间是否申请正常
        if (rx_buf == NULL)
        {
            rt_kprintf("malloc fail!\n");
            return 0;
        }
        uint8_t *rx_buf_ptr =
                rx_buf_size >= rx_len + size ?
                        rx_buf + rx_len : rx_buf;
        rx_len += rt_device_read(camera_serial, 0,
                rx_buf_ptr, size);
        result = rt_mq_recv(&camera_rx_mq, &size,
                sizeof(size), 10);
    }
#ifdef UART_DEBUG
    rt_kprintf("read:");
    for (int i = 0; i < rx_len; i++)
    {
        rt_kprintf("%02x ", (*buf_ptr)[i]);
    }
    rt_kprintf("\n");
#endif
    return rx_len;
}

void camer_read_free(void *ptr)
{
    rt_free(ptr);
}

int init()
{
    // 摄像头初始化
    camera_serial = rt_device_find("uart5");
    if (!camera_serial)
    {
        rt_kprintf("can't find uart5");
    }
    static char camera_msg_pool[256];
    rt_mq_init(&camera_rx_mq, "camera_rx_mq",
            camera_msg_pool, /* 存放消息的缓冲区 */
            sizeof(rt_size_t), /* 一条消息的最大长度 */
            sizeof(camera_msg_pool),/* 存放消息的缓冲区大小 */
            RT_IPC_FLAG_FIFO);/* 如果有多个线程等待，按照先来先得到的方法分配消息 */
    rt_device_open(camera_serial, RT_DEVICE_FLAG_INT_RX); // 中断接收方式
    rt_device_set_rx_indicate(camera_serial, cb); // 注册回调函数
    // 初始化camera封装对象
    init_ptc06(&camera, camera_write, camera_read,
            camer_read_free);
}
